<?php
/**
 * Created by PhpStorm.
 * User: liyang
 * Date: 2016/9/21
 * Time: 9:44
 */

namespace App\Libs\Tool\Impl;


use App\Libs\Tool\ReqToQueryAndParam;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

class ReqToQueryAndParamImpl implements ReqToQueryAndParam
{

    private $TIME_MIDDLE = ['>=', '<'];

    protected $request;
    protected $builder;
    protected $result_arr;
    protected $time_filed_arr;

    private $time_index = 0;
    private $time_group_index = 0;

    function __construct(Request $request, Builder $builder, $timeFiledArr = ['create_time'])
    {
        $this->request = $request;
        $this->builder = $builder;
        $this->result_arr = array();
        $this->time_filed_arr = $timeFiledArr;
    }

    /**
     * 添加一组查询对象
     *
     * 添加参数到builder，参数数组，注意：参数如果有时间参数注意开始时间必须在结束时间之前传入。
     * 多组时间，也要保证有开始必有结束。有结束必有开始，如果业务只需要其一，则另一个可以传空字符串
     *
     * 此方法会自动处理请求参数名中包含有time字符串的请求参数，但还是建议处理时间使用addTimeItem。
     *
     * @param $params
     * @return mixed
     */
    public function add($params)
    {
        // TODO: Implement add() method.
        foreach ($params as $param) {
            if ($this->request->exists($param)
                && strstr($param, 'time')
            ) {
                $this->processTime($param);
            } else {
                $this->addItem($param, $param);
            }
        }
    }

    /**
     * 添加一组模糊查询对象，add方法的扩展
     *
     * @param $params
     * @return mixed
     */
    public function addVague($params) {
        // TODO: Implement addVague() method.
        foreach ($params as $param) {
            $this->addVagueSearchItem($param, $param);
        }
    }

    /**
     * 添加一个查询对象，针对req->get值为0做了处理
     *
     * @param $dbFiled //数据库字段名称
     * @param $reqFiled //request字段名称
     * @param $val //可以自定义值，如果为空去request中对应的值
     * @return mixed
     */
    public function addItem($dbFiled, $reqFiled, $val = null)
    {
        // TODO: Implement addItem() method.
        if ($this->request->exists($reqFiled)
            && !empty($this->request->get($reqFiled))
            || $val || $this->request->get($reqFiled) === '0'
        ) {
            info('***********************value not null.' . $val);
            $this->builder->where($dbFiled, $val == null ? trim($this->request->get($reqFiled)) : $val);
        }
        $this->result_arr[$reqFiled] = $this->request->get($reqFiled);
        return $this;
    }

    /**
     * 添加一个自定义比较方法的项目
     *
     * @param $dbFiled //数据库字段名称
     * @param $reqFiled //request字段名称
     * @param null $val //可以自定义值，如果为空去request中对应的值
     * @param string $comparison //自定义比较方式，默认‘=’比较
     * @return mixed
     */
    public function addCustomComparisonMethodItem($dbFiled, $reqFiled, $val = null, $comparison = '=')
    {
        // TODO: Implement addCustomComparisonMethodItem() method.
        if ($this->request->exists($reqFiled)
            && !empty($this->request->get($reqFiled))
            || $val !== null || $this->request->get($reqFiled) === '0'
        ) {
            info('***********************value not null.' . $val);
            $this->builder->where($dbFiled, $comparison, $val === null ? trim($this->request->get($reqFiled)) : $val);
        }
        $this->result_arr[$reqFiled] = $this->request->get($reqFiled);
        return $this;
    }

    /**
     * 添加一个模糊查询对象
     *
     * @param $dbFiled              //数据库字段名称
     * @param $reqFiled             //request字段名称
     * @param null $val             //可以自定义值，如果为空去request中对应的值
     * @return mixed
     */
    public function addVagueSearchItem($dbFiled, $reqFiled, $val = null) {
        // TODO: Implement addVagueSearchItem() method.
        if ($this->request->exists($reqFiled)
            && !empty($this->request->get($reqFiled))
            || $val !== null || $this->request->get($reqFiled) === '0'
        ) {
            info('%'.trim($this->request->get($reqFiled)).'%');
            $this->builder->where($dbFiled, 'like', $val === null ? '%'.trim($this->request->get($reqFiled)).'%' : '%'.$val.'%');
        }
        $this->result_arr[$reqFiled] = $this->request->get($reqFiled);
        return $this;
    }

    /**
     * 添加映射查询对象（未完成）
     *
     * @param $dbFiled
     * @param $reqFiled
     * @param $mapping_ids
     * @return mixed
     */
    public function addMappingSearchItem($dbFiled, $reqFiled, $mapping_ids)
    {
        // TODO: Implement addMappingSearchItem() method.
    }

    /**
     * 添加一个时间查询对象，这个和add中默认的时间添加选一个用，最好别一起用。如果只查开始或结束，另一个不必填写
     *
     * @param $start_time //请求中对应的参数名称
     * @param $end_time //请求中对应的参数名称
     * @param $dbFiled
     * @return mixed
     */
    public function addTimeItem($start_time, $end_time, $dbFiled)
    {
        // TODO: Implement addTimeItem() method.
        if ($this->request->exists($start_time)
            && !empty($this->request->get($start_time))
        ) {
            $start_time_stamp = strtotime($this->request->get($start_time));
            $this->builder->where($dbFiled, '>=', $start_time_stamp);
        }
        if ($this->request->exists($end_time)
            && !empty($this->request->get($end_time))
        ) {
            $end_time_stamp = strtotime($this->request->get($end_time)) + 86400;
            $this->builder->where($dbFiled, '<', $end_time_stamp);
        }
        $this->result_arr[$start_time] = $this->request->get($start_time);
        $this->result_arr[$end_time] = $this->request->get($end_time);
        return $this;
    }

    /**
     * 大小查询
     *
     * @param $reqFiled
     * @param $dbFiled
     * @param $val //比较的值
     * @return $this
     */
    public function addSize($reqFiled, $val, $dbFiled = null)
    {
        if (!empty($this->request->exists($reqFiled))
            && !empty($this->request->get($reqFiled))
        ) {
            $compare = $this->getCompare($this->request->get($reqFiled));
            $this->builder->where(empty($dbFiled) ? $reqFiled : $dbFiled, $compare, $val);
        }
        $this->result_arr[$reqFiled] = $this->request->get($reqFiled);
        return $this;
    }

    /**
     * 获取比较方式
     *
     * @param $isBigReqFiled
     * @return null|string
     */
    private function getCompare($isBigReqFiled)
    {
        $compare = null;
        if ($isBigReqFiled == 1) {
            $compare = '>=';
        } else {
            $compare = '<';
        }
        return $compare;
    }

    /**
     * 时间处理，分别处理开始时间和结束时间，有开始必定有结束，没有结束也要填一个空的，否则无法正确识别下一个参数是开始还是结束
     *
     * @param $param
     */
    private function processTime($param)
    {
        $middle = $this->TIME_MIDDLE[$this->time_index++];
        if (!empty($this->request->get($param))) {
            $timeStamp = strtotime($this->request->get($param));
            if ($this->time_index == 2) {
                $timeStamp += 86400;
            }
            $this->builder->where($this->time_filed_arr[$this->time_group_index], $middle, $timeStamp);
        }

        $this->result_arr[$param] = $this->request->get($param);
        if ($this->time_index >= 2) {
            $this->time_index = 0;
            $this->time_group_index++;
        }
    }

    /**
     * 手工添加返回参数
     *
     * @param $paramName //参数名称
     * @param $paramValue //参数值
     */
    public function addParam($paramName, $paramValue)
    {
        $this->result_arr[$paramName] = $paramValue;
    }

    /**
     * 获取Builder对象
     *
     * @return mixed
     */
    public function getQuery()
    {
        // TODO: Implement getQuery() method.
        return $this->builder;
    }

    /**
     * 获取参数数组
     *
     * @return mixed
     */
    public function getParam()
    {
        // TODO: Implement getParam() method.
        return $this->result_arr;
    }

    /**
     * 查询返回对象
     *
     * @return QueryResult
     */
    public function getResult() {
        // TODO: Implement getResult() method.
        return new QueryResult($this->builder, $this->result_arr);
    }

    public function __clone()
    {
        // TODO: Implement __clone() method.
        $this->builder = clone $this->builder;
        foreach ($this->result_arr as $item) {
            array_push($this->result_arr, $item);
        }
        foreach ($this->time_filed_arr as $item) {
            array_push($this->time_filed_arr, $item);
        }
    }

}